/* SM2 在 (Z/256Z)* 的操作 */
#ifndef SM2_OPERATION_H
#define SM2_OPERATION_H

#include <stdint.h>
#include <stdio.h>

typedef uint32_t sm2_uint256_t[8];
typedef uint32_t sm2_uint512_t[16];

// 2^256 - n = 0x10000000000000000000000008dfc2094de39fad4ac440bf6c62abedd
extern const sm2_uint256_t SM2_256_MINUS_N;

extern const sm2_uint256_t ZERO;
extern const sm2_uint256_t ONE;
extern const sm2_uint256_t SM2_P;
extern const sm2_uint256_t SM2_A;
extern const sm2_uint256_t SM2_B;
extern const sm2_uint256_t SM2_N;
extern const sm2_uint256_t Gx;
extern const sm2_uint256_t Gy;
extern const sm2_uint256_t SM2_N_MINUS_ONE;

// 1P to 13P
extern const sm2_uint512_t SM2_Ps[13];

extern const sm2_uint512_t SM2_P_sqr;

#define SM2_COMPARE_EQ 1
#define SM2_COMPARE_GT 2
#define SM2_COMPARE_LT 3

void sm2_set_zero(sm2_uint256_t num);
void sm2_set_512_zero(sm2_uint512_t num);
void sm2_set_one(sm2_uint256_t num);
void sm2_set_512_one(sm2_uint512_t num);

void sm2_512_to_256(sm2_uint256_t result, const sm2_uint512_t n);
void sm2_256_to_512(sm2_uint512_t result, const sm2_uint256_t n);

void sm2_copy(sm2_uint256_t result, const sm2_uint256_t a);
void sm2_512_copy(sm2_uint512_t result, sm2_uint512_t a);

int sm2_compare(const sm2_uint256_t a, const sm2_uint256_t b);
int sm2_compare_512(const sm2_uint512_t a, const sm2_uint512_t b);

uint32_t sm2_add(sm2_uint256_t result, const sm2_uint256_t a, const sm2_uint256_t b);
uint32_t sm2_512_add(sm2_uint512_t result, const sm2_uint512_t a, const sm2_uint512_t b);
uint32_t sm2_sub(sm2_uint256_t result,const sm2_uint256_t a, const sm2_uint256_t b);
uint32_t sm2_512_sub(sm2_uint512_t result, const sm2_uint512_t a, const sm2_uint512_t b);
void sm2_mul(sm2_uint512_t r, const sm2_uint256_t a, const sm2_uint256_t b);

void sm2_mod_add(sm2_uint256_t result, const sm2_uint256_t a, const sm2_uint256_t b);
void sm2_mod_sub(sm2_uint256_t result, const sm2_uint256_t a, const sm2_uint256_t b);
void sm2_mod_neg(sm2_uint256_t result, const sm2_uint256_t a);
void sm2_mod_mul(sm2_uint256_t r, const sm2_uint256_t a, const sm2_uint256_t b);
void sm2_mod_sqr(sm2_uint256_t result, const sm2_uint256_t a);
void sm2_mod_k_mul(sm2_uint256_t result, const uint32_t k, const sm2_uint256_t a);

void sm2_fast_mod_reduction(sm2_uint256_t result, const sm2_uint512_t a);
void sm2_fast_mod_inverse(sm2_uint256_t result, const sm2_uint256_t a);

void sm2_modn_add(sm2_uint256_t result, const sm2_uint256_t a, const sm2_uint256_t b);
void sm2_modn_sub(sm2_uint256_t result, const sm2_uint256_t a, const sm2_uint256_t b);
void sm2_modn_neg(sm2_uint256_t result, const sm2_uint256_t a);
void sm2_modn_mont_mul(sm2_uint256_t result, const sm2_uint256_t a, const sm2_uint256_t b);
void sm2_modn_mul(sm2_uint256_t result, const sm2_uint256_t a, const sm2_uint256_t b);
void sm2_modn_mont_sqr(sm2_uint256_t result, const sm2_uint256_t a);
void sm2_modn_sqr(sm2_uint256_t result, const sm2_uint256_t a);
void sm2_modn_mont_exp(sm2_uint256_t result, const sm2_uint256_t a, const sm2_uint256_t b);
void sm2_modn_exp(sm2_uint256_t result, const sm2_uint256_t a, const sm2_uint256_t b);
void sm2_modn_mont_inverse(sm2_uint256_t result, const sm2_uint256_t a);
void sm2_modn_inverse(sm2_uint256_t result, const sm2_uint256_t a);
void sm2_modn_from_mont(sm2_uint256_t result, const sm2_uint256_t a);
void sm2_modn_to_mont(const sm2_uint256_t a, sm2_uint256_t r);

void print_256(const sm2_uint256_t n);
void print_512(const sm2_uint512_t n);
int sm2_print(FILE *fp, int ind, int fmt, const char *label, const sm2_uint256_t a);

#endif